package dhadi.use.swing;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;

import dhadi.model.Move;
import dhadi.model.Pick;
import dhadi.util.Util;

public class PickUi
{
	final int picWidth = 30;
	private Pick pick;
	private NodeUi node;
	private BoardUi board;
	private Point oldLocation = new Point(0,0);
	private Point currentLocation = new Point(0,0);
	private Rectangle bounds = new Rectangle();
	private Color color;
	public boolean isHovering;
	private boolean isMouseDraggedAfterPress;
	private boolean isMouseDragging;
	private boolean isLastMoved = false;
	
	public PickUi(Pick pick, Color color, BoardUi board)
	{
		this.pick = pick;
		this.color = color;
		this.board = board;
		this.bounds.height = picWidth;
		this.bounds.width = picWidth;
		this.setCurrentPos(0,0);
	}
	
	public void draw(Graphics g) {
		this.drawShape(g, this.bounds.x, this.bounds.y, this.bounds.width, this.bounds.height);
	}

	void applyModelChanges() {
		
		NodeUi n = this.board.layout.getNodeUi(this.pick.getNode());
		this.setNode(n);
		
		 /** 
		  * If dragging, the position is where
		  * the pick is dragged to. Otherwise
		  * the position is based on the status
		  * of the pick. For each Status the 
		  * position is 
		  * 1. Unused - does not depend on Node position
		  * 2. Onboard - Same as Node on which this Pick is
		  * 3. destroyed - does not depend on Node postion
		  */
		if (!this.isMouseDragging) {
			if (this.getPick().isOnboard()) {
				this.setCurrentPos(this.getNode().getLocation());
			}
			else if (this.getPick().isDestroyed()) {
				this.setCurrentPos(new Point(0,0));
			}
		}
	}

	private void drawShape(Graphics g, int x, int y, int w, int h) {
		
		if (this.getPick().isDestroyed()) {
			return;
		}
		
		Color oldColor = g.getColor();
		g.setColor(this.color);
		
		g.fillOval(x,y,w,h);
	
		// Bounds to draw Pick inner sprite.
		x+=3;
		y+=3;
		h-=6;
		w-=6;
		
		if (this.isMouseDragging)
		{
			g.setColor(Color.RED);
			g.fillOval(x,y,w,h);
		} 
		else if (this.isHovering)
		{
			g.setColor(Color.ORANGE);
			g.fillOval(x,y,w,h);
		}
		
		if (this.pick.getOwner().isDhadiOnYou() && 
		    this.pick.isOnboard() &&
		    /*!this.pick.getOwner().isPickFormaingDhadi(this.pick)*/
		    this.pick.getOwner().getOpponent().getPossiblePicksToKill().contains(this.pick)) { 
		    
			x = x+w/2-2;		
			y = y+h/2-2;
			
			g.setColor(Color.RED);
			g.fillOval(x-5,y-5,15,15);
			
			g.setColor(Color.WHITE);
			if (this.isHovering) g.setColor(Color.BLACK);
			
			g.drawLine(x, y, x+5, y+5);
			g.drawLine(x, y+5, x+5, y);			
		}
		
		if (this.isLastMoved()) {
			g.drawBytes("*".getBytes(), 0, 1, x, y);
		}
		
		g.setColor(oldColor);
	}

	/**
	 * If dragging, the position is where
	 * the pick is dragged to. Otherwise
	 * the position is based on the status
	 * of the pick. For each Status the 
	 * position is 
	 * 1. Unused - does not depend on Node position
	 * 2. Onboard - Same as Node on which this Pick is
	 * 3. destroyed - does not depend on Node postion
	 *	
	 * @return Point
	 */
	public Point getCurrentPos() {
		return new Point(this.bounds.x,this.bounds.y);
	}

	// Position in terms of UI, this can be any position
	// that the pick is dragged to. No constraings
	public void setCurrentPos(int x, int y) {
		this.currentLocation.x = x;
		this.currentLocation.y = y;
		this.computeBounds();
	}
	
	private void computeBounds()
	{
		this.bounds.x = this.currentLocation.x - this.bounds.width/2;
		this.bounds.y = this.currentLocation.y - this.bounds.height/2;
	}
	
	public boolean isInRegion(int x, int y)
	{
		return this.bounds.contains(x,y);
	}

	public Pick getPick() {
		return pick;
	}

	public void setPick(Pick pick) {
		this.pick = pick;
	}

	public NodeUi getNode() {
		return node;
	}

	public void setNode(NodeUi node) {
		this.node = node;
	}

	public void onMousePressed(MouseEvent e)
	{
		if (this.board.board.isGameOver()) {
			return;
		}
		
		if (this.pick.isOnboard() && this.pick.getOwner().isDhadiOnYou()) {
			Move move = 
			    Move.createKill(this.pick,
			            this.board.getBoard().currentPlayer());				
			this.board.board.move(move);
			this.board.setMovingPick(null);
		}	
		this.isMouseDragging = false;
		this.isMouseDraggedAfterPress = false;
	}
	
	public void onMouseReleased(MouseEvent e)
	{
		if (this.board.board.isGameOver()) {
			return;
		}
		
		this.isMouseDragging = false;
		if (this.isMouseDraggedAfterPress)
		{
			this.firePickDroppedEvent();
		}	
	}
	
	public void onMouseDragged(MouseEvent e)
	{
		if (this.board.board.isGameOver()) {
			return;
		}
		
		this.isMouseDraggedAfterPress = true;
		this.isMouseDragging = true;
		this.setCurrentPos(e.getX(), e.getY());
		this.firePickRollingEvent();
	}
	
	public void commitLocation(Point pivotPoint)
	{
		this.oldLocation = pivotPoint;
		this.setCurrentPos(pivotPoint.x, pivotPoint.y);
	}
	
	public void rollbackToOldLocation()
	{
		this.setCurrentPos(this.oldLocation.x, this.oldLocation.y);		
	}
	
	private List<PickListener> pickListeners = new ArrayList<PickListener>();
	public void addPickDropListener(PickListener pdl)
	{
		pickListeners.add(pdl);		
	}
	private void firePickDroppedEvent()
	{
		for (PickListener pl : pickListeners)
		{
			pl.pickDropped(this);
		}
	}
	private void firePickRollingEvent()
	{
		for (PickListener pl : pickListeners)
		{
			pl.pickRolling(this);
		}
	}
	
	public void moveToNode(NodeUi nodeUi)
	{
		/*if (this.pick.moveToNode(nodeUi.node))
		{
			this.node = nodeUi;
			this.commitLocation(nodeUi.getLocation());
		}	
		else
			this.rollbackToOldLocation();*/
	}

	public void setCurrentPos(Point location) {
		this.setCurrentPos(location.x, location.y);
	}

	public boolean isLastMoved() {
		return this.pick.isLastMoved();
	}
}